package com.kynnnn.cloud.mybatis_interceptor.util;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.kynnnn.cloud.mybatis_interceptor.annotation.EncryptDecryptField;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * <h1>加解密工具类</h1>
 *
 * @author Zhudiwei
 * @Description TODO
 * @createTime 2021年09月05日
 */
@Slf4j
public class EncryptDecryptUtils {

    private static final SymmetricCrypto SM_4 = SmUtil.sm4();

    /**
     * <h2>加密方法</h2>
     *
     * @param fields          反射bean成员变量
     * @param parameterObject Mybatis入参
     * @param <T>
     * @return
     */
    public static <T> T encrypt(Field[] fields, T parameterObject) {
        Arrays.stream(fields)
                .filter(field -> field.isAnnotationPresent(EncryptDecryptField.class))
                .forEach(field -> {
                    encrypt(field, parameterObject);
                });
        return parameterObject;
    }


    /**
     * <h2>单个field加密方法</h2>
     *
     * @param field
     * @param parameterObject
     * @param <T>
     * @return
     */
    private static <T> T encrypt(Field field, T parameterObject) {
        field.setAccessible(true);
        try {
            Object object = field.get(parameterObject);
            String fieldValue = (String) object;
            if (StringUtils.isNotEmpty(fieldValue)) {
                // 加密
                fieldValue = SM_4.encryptHex(fieldValue);
                field.set(parameterObject, fieldValue);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return parameterObject;
    }


    /**
     * <h2>解密方法</h2>
     *
     * @param result Mybatis 返回值，需要判断是否是ArrayList类型
     * @param <T>
     * @return
     */
    public static <T> T decrypt(T result) {
        Class<?> clazz = result.getClass();
        Field[] fields = clazz.getDeclaredFields();
        decrypt(fields, result);
        return result;
    }

    /**
     * <h2>多个field解密方法</h2>
     *
     * @param fields
     * @param result
     */
    private static void decrypt(Field[] fields, Object result) {
        Arrays.stream(fields)
                .filter(field -> field.isAnnotationPresent(EncryptDecryptField.class))
                .forEach(field -> {
                    decrypt(field, result);
                });
    }

    /**
     * 单个field解密方法
     *
     * @param field
     * @param result
     * @throws IllegalAccessException
     */
    private static void decrypt(Field field, Object result) {
        field.setAccessible(true);
        Object object = null;
        try {
            object = field.get(result);

            String fieldValue = (String) object;
            if (StringUtils.isNotEmpty(fieldValue)) {
                // 解密
                fieldValue = SM_4.decryptStr(fieldValue, CharsetUtil.CHARSET_UTF_8);
                field.set(result, fieldValue);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


}
